/*
 * 1.00 2012/10/18
 *
 * Copyright (c) 2012 Motch_bs
 * All rights reserved.
 *
 * このソフトウェアは，Motch_bsに所有される機密情報である。
 * これらの機密情報を漏洩してはならず，Motch_bs の意図する
 * 認可の元においてこれを使用すべし。
 */
package jp.co.ufp.voicetch.base.audio;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import jp.co.ufp.jnilib.EffectVoice;

/**
 * @author Motch_bs
 * 
 */
public class Converter {

    /** ピッチシフトライブラリ */
    private EffectVoice effectVoice = new EffectVoice();

    /**
     * short型配列からdouble型配列
     * 
     * @param s
     * @return
     */
    public double[] shortToDouble(
	short[] s) {
	int len = s.length;
	double[] ret = new double[len];
	for (int i = 0; i < len; i++) {
	    ret[i] = (double) s[i];
	}
	return ret;
    }

    /**
     * C++ライブラリで変換
     * 
     * @param data
     * @return
     */
    public short[] pitchShift_cpp(
	short[] data) {
	float[] nf1 = new float[data.length];
	for (int cnt = 0; cnt < nf1.length; cnt++) {
	    nf1[cnt] = Short.valueOf(data[cnt]).floatValue();
	}
	float[] nf2 = effectVoice.equalize(nf1);
	short[] ns = new short[nf2.length];
	for (int cnt = 0; cnt < nf2.length; cnt++) {
	    ns[cnt] = Float.valueOf(nf2[cnt]).shortValue();
	}
	return ns;
    }

    /**
     * Javaライブラリで変換
     * 
     * @param data
     * @param frequency
     * @return
     */
    public short[] pitchShift_java(
	short[] data, int frequency) {
	double[] inData = new double[data.length];
	double[] outData = new double[data.length];
	short[] convData = new short[data.length];
	for (int cnt = 0; cnt < inData.length; cnt++) {
	    inData[cnt] = Integer.valueOf(data[cnt]).doubleValue();
	}

	PitchShift pitchShift = new PitchShift(data.length);
	// pitchShift.smbFft(fft, musicLength, 1);
	pitchShift.setSampleRate(frequency);
	outData = pitchShift.smbPitchShift(inData, 0, data.length);
	for (int cnt = 0; cnt < inData.length; cnt++) {
	    convData[cnt] = Double.valueOf(outData[cnt]).shortValue();
	}
	return convData;
    }

    /**
     * Wavファイルのヘッダを作成する（PCM16ビット モノラル）
     * 
     * @param sampleRate
     * @param datasize
     * @return
     */
    public byte[] createWavHeader(
	int sampleRate, int datasize) {
	byte[] byteRIFF = {
	    'R',
	    'I',
	    'F',
	    'F'
	};
	byte[] byteFilesizeSub8 = intToBytesForWav((datasize + 36)); // ファイルサイズ-8バイト数
	byte[] byteWAVE = {
	    'W',
	    'A',
	    'V',
	    'E'
	};
	byte[] byteFMT_ = {
	    'f',
	    'm',
	    't',
	    ' '
	};
	// fmtチャンクのバイト数
	byte[] byte16bit = intToBytesForWav(16);
	// サンプルレート
	byte[] byteSamplerate = intToBytesForWav(sampleRate);
	// バイト/秒 = サンプルレートx 1チャンネル x 2バイト
	byte[] byteBytesPerSec = intToBytesForWav(sampleRate * 2);
	byte[] bytePcmMono = {
	    0x01,
	    0x00,
	    0x01,
	    0x00
	}; // フォーマットID 1 =リニアPCM , チャンネル 1 = モノラル
	byte[] byteBlockBit = {
	    0x02,
	    0x00,
	    0x10,
	    0x00
	}; // ブロックサイズ2バイト サンプルあたりのビット数16ビット
	byte[] byteDATA = {
	    'd',
	    'a',
	    't',
	    'a'
	};
	byte[] byteDatasize = intToBytesForWav(datasize); // データサイズ

	ByteArrayOutputStream out = new ByteArrayOutputStream();
	try {
	    out.write(byteRIFF);
	    out.write(byteFilesizeSub8);
	    out.write(byteWAVE);
	    out.write(byteFMT_);
	    out.write(byte16bit);
	    out.write(bytePcmMono);
	    out.write(byteSamplerate);
	    out.write(byteBytesPerSec);
	    out.write(byteBlockBit);
	    out.write(byteDATA);
	    out.write(byteDatasize);

	}
	catch (IOException e) {
	    return out.toByteArray();
	}

	return out.toByteArray();
    }

    /**
     * int型32ビットデータをリトルエンディアンのバイト配列にする
     * 
     * @param value
     * @return byte[]
     */
    private byte[] intToBytesForWav(
	int value) {
	byte[] bt = new byte[4];
	bt[0] = (byte) (value & 0x000000ff);
	bt[1] = (byte) ((value & 0x0000ff00) >> 8);
	bt[2] = (byte) ((value & 0x00ff0000) >> 16);
	bt[3] = (byte) ((value & 0xff000000) >> 24);
	return bt;
    }
}
